/*
 *Copyright (c) 2024 Black Sesame Technologies
 *
 *Licensed under the Apache License, Version 2.0 (the "License");
 *you may not use this file except in compliance with the License.
 *You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 *Unless required by applicable law or agreed to in writing, software
 *distributed under the License is distributed on an "AS IS" BASIS,
 *WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *See the License for the specific language governing permissions and
 *limitations under the License.
*/

/*==================================================================================================
*                                        INCLUDE FILES
* 1) system and project includes
* 2) needed interfaces from external units
* 3) internal and external interfaces from this unit
==================================================================================================*/
#include <string.h>
#include "../../library/printf_inc.h"
#include "../hscg_flexcan/Can_HSCG.h"
#include "../hscg_flexcan/Can_HSCG_IPW.h"
#include "../hscg_flexcan/Hscg_InterfaceFifo.h"
#include "../hscg_flexcan/Hscg_SwFifo.h"
#include "../hscg_flexcan/FlexCAN_Ip.h"
#include "../hscg_flexcan/C1200_Flexcan.h"
#include "hscg_firmware_statistic.h"

/* Table of base addresses for CAN instances. */
FLEXCAN_Type * const Flexcan_Ip_apxBase[] = IP_SWITCH_FLEXCAN_BASE_PTRS;

/*FUNCTION**********************************************************************
 *
 * Function Name: FLEXCAN_ComputeDLCValue
 * Description  : Computes the DLC field value, given a payload size (in bytes).
 *
 *END**************************************************************************/
static uint8 FlexCAN_ComputeDLCValue(uint8 payloadSize)
{
    uint32 ret = 0xFFU;                   /* 0,  1,  2,  3,  4,  5,  6,  7,  8, */
    static const uint8 payload_code[65] = {0U, 1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U,
                                           /* 9 to 12 payload have DLC Code 12 Bytes */
                                           FLEXCAN_IP_DLC_VALUE_12_BYTES, FLEXCAN_IP_DLC_VALUE_12_BYTES, FLEXCAN_IP_DLC_VALUE_12_BYTES, FLEXCAN_IP_DLC_VALUE_12_BYTES,
                                           /* 13 to 16 payload have DLC Code 16 Bytes */
                                           FLEXCAN_IP_DLC_VALUE_16_BYTES, FLEXCAN_IP_DLC_VALUE_16_BYTES, FLEXCAN_IP_DLC_VALUE_16_BYTES, FLEXCAN_IP_DLC_VALUE_16_BYTES,
                                           /* 17 to 20 payload have DLC Code 20 Bytes */
                                           FLEXCAN_IP_DLC_VALUE_20_BYTES, FLEXCAN_IP_DLC_VALUE_20_BYTES, FLEXCAN_IP_DLC_VALUE_20_BYTES, FLEXCAN_IP_DLC_VALUE_20_BYTES,
                                           /* 21 to 24 payload have DLC Code 24 Bytes */
                                           FLEXCAN_IP_DLC_VALUE_24_BYTES, FLEXCAN_IP_DLC_VALUE_24_BYTES, FLEXCAN_IP_DLC_VALUE_24_BYTES, FLEXCAN_IP_DLC_VALUE_24_BYTES,
                                           /* 25 to 32 payload have DLC Code 32 Bytes */
                                           FLEXCAN_IP_DLC_VALUE_32_BYTES, FLEXCAN_IP_DLC_VALUE_32_BYTES, FLEXCAN_IP_DLC_VALUE_32_BYTES, FLEXCAN_IP_DLC_VALUE_32_BYTES,
                                           FLEXCAN_IP_DLC_VALUE_32_BYTES, FLEXCAN_IP_DLC_VALUE_32_BYTES, FLEXCAN_IP_DLC_VALUE_32_BYTES, FLEXCAN_IP_DLC_VALUE_32_BYTES,
                                           /* 33 to 48 payload have DLC Code 48 Bytes */
                                           FLEXCAN_IP_DLC_VALUE_48_BYTES, FLEXCAN_IP_DLC_VALUE_48_BYTES, FLEXCAN_IP_DLC_VALUE_48_BYTES, FLEXCAN_IP_DLC_VALUE_48_BYTES,
                                           FLEXCAN_IP_DLC_VALUE_48_BYTES, FLEXCAN_IP_DLC_VALUE_48_BYTES, FLEXCAN_IP_DLC_VALUE_48_BYTES, FLEXCAN_IP_DLC_VALUE_48_BYTES,
                                           FLEXCAN_IP_DLC_VALUE_48_BYTES, FLEXCAN_IP_DLC_VALUE_48_BYTES, FLEXCAN_IP_DLC_VALUE_48_BYTES, FLEXCAN_IP_DLC_VALUE_48_BYTES,
                                           FLEXCAN_IP_DLC_VALUE_48_BYTES, FLEXCAN_IP_DLC_VALUE_48_BYTES, FLEXCAN_IP_DLC_VALUE_48_BYTES, FLEXCAN_IP_DLC_VALUE_48_BYTES,
                                           /* 49 to 64 payload have DLC Code 64 Bytes */
                                           FLEXCAN_IP_DLC_VALUE_64_BYTES, FLEXCAN_IP_DLC_VALUE_64_BYTES, FLEXCAN_IP_DLC_VALUE_64_BYTES, FLEXCAN_IP_DLC_VALUE_64_BYTES,
                                           FLEXCAN_IP_DLC_VALUE_64_BYTES, FLEXCAN_IP_DLC_VALUE_64_BYTES, FLEXCAN_IP_DLC_VALUE_64_BYTES, FLEXCAN_IP_DLC_VALUE_64_BYTES,
                                           FLEXCAN_IP_DLC_VALUE_64_BYTES, FLEXCAN_IP_DLC_VALUE_64_BYTES, FLEXCAN_IP_DLC_VALUE_64_BYTES, FLEXCAN_IP_DLC_VALUE_64_BYTES,
                                           FLEXCAN_IP_DLC_VALUE_64_BYTES, FLEXCAN_IP_DLC_VALUE_64_BYTES, FLEXCAN_IP_DLC_VALUE_64_BYTES, FLEXCAN_IP_DLC_VALUE_64_BYTES
                                          };

    if (payloadSize <= 64U)
    {
        ret = payload_code[payloadSize];
    }
    else
    {
        /* The argument is not a valid payload size will return 0xFF*/
    }

    return (uint8)ret;
}


/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_ClearRAM
 * Description   : Clears FlexCAN memory positions that require initialization.
 *
 *END**************************************************************************/
static void FlexCAN_ClearRAM(FLEXCAN_Type * base)
{
    uint32 databyte;
    /* Address of base + ram offset to point to MB start address */
    volatile uint32 * RAM = (uint32 *)((uint32)base + (uint32)FLEXCAN_IP_FEATURE_RAM_OFFSET);

    // Enable CANFD
    base->MCR = (base->MCR & ~FLEXCAN_MCR_FDEN_MASK) | FLEXCAN_MCR_FDEN(1U);

    // Init ECC RAM
    base->CTRL2 = (base->CTRL2 & ~FLEXCAN_CTRL2_WRMFRZ_MASK) | FLEXCAN_CTRL2_WRMFRZ(1U);

    // Set CTRL2[ECRWRE]
    base->CTRL2 = (base->CTRL2 & ~FLEXCAN_CTRL2_ECRWRE_MASK) | FLEXCAN_CTRL2_ECRWRE(1);

    // Clear MECR[ECRWRDIS]
    base->MECR = (base->MECR & ~FLEXCAN_MECR_ECRWRDIS_MASK) | FLEXCAN_MECR_ECRWRDIS(0);
    
    // ECC Memery
    // 0x0080~0x0AAC
    RAM = (volatile uint32_t *)((uint32_t)&base->MCR + 0x0080);
    for (databyte = 0; databyte <= (0x0AAC-0x0080)/4; databyte++) {
        RAM[databyte] = 0x0;
    }

    // 0x0F28~0x0FFC
    RAM = (volatile uint32_t *)((uint32_t)&base->MCR + 0x0F28);
    for (databyte = 0; databyte <= (0x0FFC-0x0F28)/4; databyte++) {
        RAM[databyte] = 0x0;
    }

    // 0x1000~0x17FF
    RAM = (volatile uint32_t *)((uint32_t)&base->MCR + 0x1000);
    for (databyte = 0; databyte <= (0x17FF-0x1000)/4; databyte++) {
        RAM[databyte] = 0x0;
    }

    // 0x2000~0x29FC
    RAM = (volatile uint32_t *)((uint32_t)&base->MCR + 0x2000);
    for (databyte = 0; databyte <= (0x29FC-0x2000)/4; databyte++) {
        RAM[databyte] = 0x0;
    }

    // 0x3000~0x31FC
    RAM = (volatile uint32_t *)((uint32_t)&base->MCR + 0x3000);
    for (databyte = 0; databyte <= (0x31FC-0x3000)/4; databyte++) {
        RAM[databyte] = 0x0;
    }

    // 0x0C20~0x0C24
    RAM = (volatile uint32_t *)((uint32_t)&base->MCR + 0x0C20);
    RAM[0] = 0x00;
    RAM[1] = 0x00;

    // 0x0C30~0x0E2C
    RAM = (volatile uint32_t *)((uint32_t)&base->MCR + 0x0C30);
    for (databyte = 0; databyte <= (0x0E2C-0x0C30)/4; databyte++) {
        RAM[databyte] = 0x0;
    }

    // Disable CANFD
    base->MCR = (base->MCR & ~FLEXCAN_MCR_FDEN_MASK) | FLEXCAN_MCR_FDEN(0U);

    // Clear CTRL2[ECRWRE]
    base->CTRL2 = (base->CTRL2 & ~FLEXCAN_CTRL2_ECRWRE_MASK) | FLEXCAN_CTRL2_ECRWRE(0);

}


/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_ComputePayloadSize
 * Description   : Computes the maximum payload size (in bytes), given a DLC
 * field value.
 *
 *END**************************************************************************/
uint8 FlexCAN_ComputePayloadSize(uint8 dlcValue)
{
    uint8 ret = 8U;

    if (dlcValue <= 8U)
    {
        ret = dlcValue;
    }
    else
    {
        switch (dlcValue)
        {
            case FLEXCAN_IP_DLC_VALUE_12_BYTES:
                ret = 12U;
                break;
            case FLEXCAN_IP_DLC_VALUE_16_BYTES:
                ret = 16U;
                break;
            case FLEXCAN_IP_DLC_VALUE_20_BYTES:
                ret = 20U;
                break;
            case FLEXCAN_IP_DLC_VALUE_24_BYTES:
                ret = 24U;
                break;
            case FLEXCAN_IP_DLC_VALUE_32_BYTES:
                ret = 32U;
                break;
            case FLEXCAN_IP_DLC_VALUE_48_BYTES:
                ret = 48U;
                break;
            case FLEXCAN_IP_DLC_VALUE_64_BYTES:
                ret = 64U;
                break;
            default:
                /* The argument is not a valid DLC size */
                break;
        }
    }
    return ret;
}


/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_GetPayloadSize
 * Description   : Returns the payload size of the MBs (in bytes).
 *
 *END**************************************************************************/
static uint8 FlexCAN_GetPayloadSize(const FLEXCAN_Type * base, uint8 mbdsrIdx)
{
    uint32 payloadSize = 8U;

    if(base->FDCTRL & FLEXCAN_FDCTRL_MBDSR0_MASK)
    {
        payloadSize = 64U;
    }
    return (uint8)payloadSize;
}


/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_GetMsgBuffRegion
 * Description   : Returns the start of a MB area, based on its index.
 *
 *END**************************************************************************/
volatile uint32 * FlexCAN_GetMsgBuffRegion(const FLEXCAN_Type * base, uint32 msgBuffIdx)
{
    uint8 arbitration_field_size = 8U;
    uint8 mb_size = 0U;
    uint32 ramBlockSize = 512U;
    uint32 ramBlockOffset = 0;
    uint32 msgBuffIdxBackup = msgBuffIdx;
    uint8 i=0U;
    uint8 maxMbNum=0U;
    uint32 mb_index=0U;
    uint8 payload_size=0U;
    volatile uint32 * RAM = (uint32*)((uint32)base + (uint32)FLEXCAN_IP_FEATURE_RAM_OFFSET);
    volatile uint32 * pAddressRet = NULL_PTR;


    payload_size = FlexCAN_GetPayloadSize(base, i);

    if(payload_size != 64) {
        hprintf(DEBUG, "error, mb payload size should be 64 but is %d\n", payload_size);
        return 0;
    }

    /**
     * 根据FLEXCAN数据手册"FlexCAN Message Buffer Memory Map"章节，MB的地址为：
     * (64Byte)时
     * MB 0~27 :base+0x80 ~ base+0x830 （每个MB占用空间0x48,且每隔7个MB，offset要增加0x8)
     * MB28~55 :base+0x1000 ~ base+17B0 （每个MB占用空间0x48)
    */
   uint32 offset, group,index;
    if(msgBuffIdx <=27) {
        offset = 0x80;
        group = msgBuffIdx/7;
        index = msgBuffIdx;
    } else if(msgBuffIdx > 27 && msgBuffIdx < 56) {
        offset = 0x1000;
        group = (msgBuffIdx-28)/7;
        index = msgBuffIdx-28;
    } else {
        hprintf(DEBUG, "error msgBuffIdx should be 0~55 but is %d\n", msgBuffIdx);
        return 0;
    }

    pAddressRet = (uint8*)base + offset + index*0x48 + group*0x8;

    // if(64U == payload_size)
    // {
    //     // Payload Size = 64Byte
    //     mb_index = ((msgBuffIdx/7)*128) + (msgBuffIdx%7)*18;
    // }
    // else
    // {
    //     // Payload Size = 8Byte
    //     mb_index = msgBuffIdx*4;
    // }
    // pAddressRet = &(RAM[mb_index]);

    return pAddressRet;
}

/*!
 * @brief Clears the interrupt flag of the message buffers.
 *
 * @param   base        The FlexCAN base address
 * @param   msgBuffIdx  Index of the message buffer
 */
static inline void FlexCAN_ClearMsgBuffIntStatusFlag(FLEXCAN_Type * base, uint32 msgBuffIdx)
{
    uint32 flag = ((uint32)1U << (msgBuffIdx % 32U));

    /* Clear the corresponding message buffer interrupt flag*/
    if (msgBuffIdx < 32U)
    {
        (base->IFLAG1) = (flag);
    }
    else if (msgBuffIdx < 64U)
    {
        (base->IFLAG2) = (flag);
    }
}


/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_StartSendData
 * Description   : Initiate (start) a transmit by beginning the process of
 * sending data.
 * This is not a public API as it is called from other driver functions.
 *
 *END**************************************************************************/
static Flexcan_Ip_StatusType FlexCAN_StartSendData(uint8 Flexcan_Ip_u8Instance,
                                                   uint8 mb_idx,
                                                   const Flexcan_Ip_DataInfoType * tx_info,
                                                   uint32 msg_id,
                                                   const uint8 * mb_data
                                                  )
{
    Flexcan_Ip_StatusType eResult = FLEXCAN_STATUS_SUCCESS;
    Flexcan_Ip_MsbuffCodeStatusType cs;
    FLEXCAN_Type * base = Flexcan_Ip_apxBase[Flexcan_Ip_u8Instance];
    volatile uint32 * pMbAddr = NULL_PTR;


    /* Clear message buffer flag */
    FlexCAN_ClearMsgBuffIntStatusFlag(base, mb_idx);


    cs.dataLen = tx_info->data_length;

    cs.msgIdType = tx_info->msg_id_type;


    if (tx_info->is_remote)
    {
        cs.code = (uint32)FLEXCAN_TX_REMOTE;
    }
    else
    {
        cs.code = (uint32)FLEXCAN_TX_DATA;
    }
    pMbAddr = FlexCAN_GetMsgBuffRegion(base, mb_idx);
    FlexCAN_SetTxMsgBuff(pMbAddr, &cs, msg_id, mb_data, FALSE);

    return eResult;
}


/*FUNCTION**********************************************************************
 *
 * Function Name : FlexCAN_DRV_Send
 * Description   : This function sends a CAN frame using a configured message
 * buffer. The function returns immediately. If a callback is installed, it will
 * be invoked after the frame was sent.
 *
 *END**************************************************************************/
/* implements FlexCAN_Ip_Send_Activity */
Flexcan_Ip_StatusType FlexCAN_Ip_Send(uint8 instance,
                                      uint8 mb_idx,
                                      const Flexcan_Ip_DataInfoType * tx_info,
                                      uint32 msg_id,
                                      const uint8 * mb_data
                                     )
{
    Flexcan_Ip_StatusType result = FLEXCAN_STATUS_ERROR;
#if (FLEXCAN_IP_MB_INTERRUPT_SUPPORT == STD_ON)
    FLEXCAN_Type * base = Flexcan_Ip_apxBase[instance];
    const Flexcan_Ip_StateType * state = Flexcan_Ip_apxState[instance];
#else
    const FLEXCAN_Type * base = Flexcan_Ip_apxBase[instance];
#endif

#if (FLEXCAN_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(instance < FLEXCAN_INSTANCE_COUNT);
    DevAssert(tx_info != NULL_PTR);
#endif
    result = FlexCAN_StartSendData(instance, mb_idx, tx_info, msg_id, mb_data);
    return result;
}


/*FUNCTION**********************************************************************
 *
 * Function Name : FlexCAN_IsEnabled
 * Description   : Enter the freeze mode.
 *
 *END**************************************************************************/
static inline boolean FlexCAN_IsEnabled(const FLEXCAN_Type * pBase)
{
    return (((pBase->MCR & FLEXCAN_MCR_MDIS_MASK) >> FLEXCAN_MCR_MDIS_SHIFT) != 0U) ? FALSE : TRUE;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FlexCAN_IsEnabled
 * Description   : Enter the freeze mode.
 *
 *END**************************************************************************/
void FlexCAN_ConfigCtrlOptions(FLEXCAN_Type * pBase, uint32 u32Options)
{

}


/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_EnterFreezeMode
 * Description   : Enter the freeze mode.
 *
 *END**************************************************************************/
Flexcan_Ip_StatusType FlexCAN_EnterFreezeMode(FLEXCAN_Type * base)
{
    uint32 timeStart = 0U;
    uint32 timeElapsed = 0U;
    Flexcan_Ip_StatusType returnResult = FLEXCAN_STATUS_SUCCESS;

    base->MCR = (base->MCR & ~FLEXCAN_MCR_FRZ_MASK) | FLEXCAN_MCR_FRZ(1U);
    base->MCR = (base->MCR & ~FLEXCAN_MCR_HALT_MASK) | FLEXCAN_MCR_HALT(1U);
    if (((base->MCR & FLEXCAN_MCR_MDIS_MASK) >> FLEXCAN_MCR_MDIS_SHIFT) != 0U)
    {
        base->MCR &= ~FLEXCAN_MCR_MDIS_MASK;
    }

    /* Wait for entering the freeze mode */
    timeStart = 0x00;
    while (0U == ((base->MCR & FLEXCAN_MCR_FRZACK_MASK) >> FLEXCAN_MCR_FRZACK_SHIFT))
    {
        timeElapsed++;
        if (timeElapsed >= FLEXCAN_IP_SERVICE_TIMEOUT_TYPE)
        {
            returnResult = FLEXCAN_STATUS_TIMEOUT;
            break;
        }
    }

    return returnResult;
}


/*FUNCTION**********************************************************************
 *
 * Function Name : FlexCAN_Enable
 * Description   : Enable the clock for FlexCAN Module.
 *
 *END**************************************************************************/
Flexcan_Ip_StatusType FlexCAN_Enable(FLEXCAN_Type * base)
{
    uint32 timeStart = 0U;
    uint32 timeElapsed = 0U;
    Flexcan_Ip_StatusType returnValue = FLEXCAN_STATUS_SUCCESS;

    /* Enable Module */
    base->MCR &= ~FLEXCAN_MCR_MDIS_MASK;

    /* Wait for entering the freeze mode */
    timeStart = 0x00;
    while (0U == ((base->MCR & FLEXCAN_MCR_FRZACK_MASK) >> FLEXCAN_MCR_FRZACK_SHIFT))
    {
        timeElapsed++;
        if (timeElapsed >= FLEXCAN_IP_SERVICE_TIMEOUT_TYPE)
        {
            returnValue = FLEXCAN_STATUS_TIMEOUT;
            break;
        }
    }
    return returnValue;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_ExitFreezeMode
 * Description   : Exit of freeze mode.
 *
 *END**************************************************************************/
Flexcan_Ip_StatusType FlexCAN_ExitFreezeMode(FLEXCAN_Type * base)
{
    uint32 timeStart = 0U;
    uint32 timeElapsed = 0U;
    Flexcan_Ip_StatusType returnValue = FLEXCAN_STATUS_SUCCESS;

    base->MCR = (base->MCR & ~FLEXCAN_MCR_HALT_MASK) | FLEXCAN_MCR_HALT(0U);
    base->MCR = (base->MCR & ~FLEXCAN_MCR_FRZ_MASK) | FLEXCAN_MCR_FRZ(0U);

    /* Wait till exit freeze mode */
    timeStart = 0x00;
    while (((base->MCR & FLEXCAN_MCR_FRZACK_MASK) >> FLEXCAN_MCR_FRZACK_SHIFT) != 0U)
    {
        timeElapsed++;
        if (timeElapsed >= FLEXCAN_IP_SERVICE_TIMEOUT_TYPE)
        {
            returnValue = FLEXCAN_STATUS_TIMEOUT;
            break;
        }
    }
    return returnValue;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_Disable
 * Description   : Disable FlexCAN module.
 * This function will disable FlexCAN module.
 *
 *END**************************************************************************/
Flexcan_Ip_StatusType FlexCAN_Disable(FLEXCAN_Type * base)
{
    uint32 timeStart = 0U;
    uint32 timeElapsed = 0U;
    Flexcan_Ip_StatusType returnResult = FLEXCAN_STATUS_SUCCESS;

    /* To access the memory mapped registers */
    /* Enter disable mode (hard reset). */
    if (0U == ((base->MCR & FLEXCAN_MCR_MDIS_MASK) >> FLEXCAN_MCR_MDIS_SHIFT))
    {
        /* Clock disable (module) */
        base->MCR = (base->MCR & ~FLEXCAN_MCR_MDIS_MASK) | FLEXCAN_MCR_MDIS(1U);
        /* Wait until disable mode acknowledged */
        timeStart = 0x00;
        while (0U == ((base->MCR & FLEXCAN_MCR_LPMACK_MASK) >> FLEXCAN_MCR_LPMACK_SHIFT))
        {
            timeElapsed++;
            if (timeElapsed >= FLEXCAN_IP_SERVICE_TIMEOUT_TYPE)
            {
                returnResult = FLEXCAN_STATUS_TIMEOUT;
                break;
            }
        }
    }
    return returnResult;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_Init
 * Description   : Initialize FlexCAN module.
 * This function will reset FlexCAN module, set maximum number of message
 * buffers, initialize all message buffers as inactive, enable RX FIFO
 * if needed, mask all mask bits, and disable all MB interrupts.
 *
 *END**************************************************************************/
Flexcan_Ip_StatusType FlexCAN_Init(FLEXCAN_Type * base)
{
    uint32 timeStart = 0U;
    uint32 timeElapsed = 0U;
    Flexcan_Ip_StatusType returnResult = FLEXCAN_STATUS_SUCCESS;

    /* Reset the FLEXCAN */
    base->MCR = (base->MCR & ~FLEXCAN_MCR_SOFTRST_MASK) | FLEXCAN_MCR_SOFTRST(1U);
    /* Wait for reset cycle to complete */
    timeStart = 0x00;
    while (((base->MCR & FLEXCAN_MCR_SOFTRST_MASK) >> FLEXCAN_MCR_SOFTRST_SHIFT) != 0U)
    {
        timeElapsed++;
        if (timeElapsed >= FLEXCAN_IP_SERVICE_TIMEOUT_TYPE)
        {
            returnResult = FLEXCAN_STATUS_TIMEOUT;
            break;
        }
    }

    if (FLEXCAN_STATUS_SUCCESS == returnResult)
    {
        /* Avoid Abort Transmission, use Inactive MB */
        base->MCR = (base->MCR & ~FLEXCAN_MCR_AEN_MASK) | FLEXCAN_MCR_AEN(1U);
        /* Clear FlexCAN memory */
        FlexCAN_ClearRAM(base);
        /* Rx global mask*/
        (base->RXMGMASK) = (uint32)(FLEXCAN_RXMGMASK_MG_MASK);
        /* Rx reg 14 mask*/
        (base->RX14MASK) =  (uint32)(FLEXCAN_RX14MASK_RX14M_MASK);
        /* Rx reg 15 mask*/
        (base->RX15MASK) = (uint32)(FLEXCAN_RX15MASK_RX15M_MASK);
        
        /* Disable all MB interrupts & Clear all MB interrupt flags */
        (base->IMASK1) = 0x0;
        (base->IFLAG1) = FLEXCAN_IMASK1_BUF31TO0M_MASK;     
        (base->IMASK2) = 0x0;
        (base->IFLAG2) = FLEXCAN_IMASK2_BUF63TO32M_MASK;
        (base->IMASK3) = 0x0;
        (base->IFLAG3) = FLEXCAN_IMASK3_BUF95TO64M_MASK;
        (base->IMASK4) = 0x0;
        (base->IFLAG4) = FLEXCAN_IMASK4_BUF127TO96M_MASK;


        /* Clear all error interrupt flags */
        (base->ESR1) = FLEXCAN_IP_ALL_INT;
        /* clear registers which are not effected by soft reset */
        base->CTRL1 = FLEXCAN_IP_CTRL1_DEFAULT_VALUE_U32;
        base->CTRL2 = FLEXCAN_IP_CTRL2_DEFAULT_VALUE_U32;
        base->CBT   = FLEXCAN_IP_CBT_DEFAULT_VALUE_U32;

        base->EPRS  = FLEXCAN_IP_EPRS_DEFAULT_VALUE_U32;
        base->ENCBT = FLEXCAN_IP_ENCBT_DEFAULT_VALUE_U32;
        base->EDCBT = FLEXCAN_IP_EDCBT_DEFAULT_VALUE_U32;
        base->ETDC  = FLEXCAN_IP_ETDC_DEFAULT_VALUE_U32;
        base->FDCBT = FLEXCAN_IP_FDCBT_DEFAULT_VALUE_U32;
        base->FDCTRL = FLEXCAN_IP_FDCTRL_DEFAULT_VALUE_U32;

    }
    return returnResult;
}


/*FUNCTION**********************************************************************
 *
 * Function Name : FlexCAN_InitCtroll
 * Description   : Initialize basically controller.
 *
 * This is not a public API as it is called from other driver functions.
 *END**************************************************************************/
static Flexcan_Ip_StatusType FlexCAN_InitCtroll(FLEXCAN_Type * pBase, Hscg_Can_InitCmdType* pChannelInitConfig)
{
    Flexcan_Ip_StatusType eResult = FLEXCAN_STATUS_SUCCESS;
    
    //ensble canfd.
    pBase->MCR = (pBase->MCR & ~FLEXCAN_MCR_FDEN_MASK) | FLEXCAN_MCR_FDEN(1);
    //iso
    pBase->CTRL2 = (pBase->CTRL2 & ~FLEXCAN_CTRL2_ISOCANFDEN_MASK) | FLEXCAN_CTRL2_ISOCANFDEN(1);
    
    pBase->FDCTRL = (pBase->FDCTRL & ~FLEXCAN_FDCTRL_MBDSR0_MASK) | FLEXCAN_FDCTRL_MBDSR0(3);
    pBase->FDCTRL = (pBase->FDCTRL & ~FLEXCAN_FDCTRL_MBDSR1_MASK) | FLEXCAN_FDCTRL_MBDSR1(3);
    pBase->FDCTRL = (pBase->FDCTRL & ~FLEXCAN_FDCTRL_MBDSR2_MASK) | FLEXCAN_FDCTRL_MBDSR2(3);
    pBase->FDCTRL = (pBase->FDCTRL & ~FLEXCAN_FDCTRL_MBDSR3_MASK) | FLEXCAN_FDCTRL_MBDSR3(3);

    // set lookback mode
    pBase->CTRL1 = (pBase->CTRL1 & ~FLEXCAN_CTRL1_LPB_MASK) | FLEXCAN_CTRL1_LPB(0U);

    /* Disable the self reception feature if FlexCAN is not in loopback mode. */
    pBase->MCR = (pBase->MCR & ~FLEXCAN_MCR_SRXDIS_MASK) | FLEXCAN_MCR_SRXDIS(1UL);

    // Set MB
    pBase->MCR = (pBase->MCR & ~FLEXCAN_MCR_MAXMB_MASK) | FLEXCAN_MCR_MAXMB(55U);

    // Disable Legacy Fifo
    pBase->MCR = (pBase->MCR & ~FLEXCAN_MCR_RFEN_MASK) | FLEXCAN_MCR_RFEN(0);

    // 
    pBase->MCR = (pBase->MCR & ~FLEXCAN_MCR_IRMQ_MASK) | FLEXCAN_MCR_IRMQ(1U);

    // Test
    // Enhanced FIFO
    pBase->ERFCR = (pBase->ERFCR & ~FLEXCAN_ERFCR_ERFEN_MASK) | FLEXCAN_ERFCR_ERFEN(1);

    // Reset Enhanced Rx FIFO engine
    pBase->ERFSR = (pBase->ERFSR & ~FLEXCAN_ERFSR_ERFCLR_MASK) | FLEXCAN_ERFSR_ERFCLR(1);

    // Clear ERFSR:ERFUFW,ERFOVF,ERFWMI,ERFDA
    pBase->ERFSR = (pBase->ERFSR & ~FLEXCAN_ERFSR_ERFUFW_MASK) | FLEXCAN_ERFSR_ERFUFW(0);
    pBase->ERFSR = (pBase->ERFSR & ~FLEXCAN_ERFSR_ERFOVF_MASK) | FLEXCAN_ERFSR_ERFOVF(0);
    pBase->ERFSR = (pBase->ERFSR & ~FLEXCAN_ERFSR_ERFWMI_MASK) | FLEXCAN_ERFSR_ERFWMI(0);
    pBase->ERFSR = (pBase->ERFSR & ~FLEXCAN_ERFSR_ERFDA_MASK) | FLEXCAN_ERFSR_ERFDA(0);

    return eResult;
}


/*FUNCTION**********************************************************************
 *
 * Function Name : FlexCAN_SetEnhancedNominalTimeSegments
 * Description   : Initialize basically controller.
 *
 *END**************************************************************************/
void FlexCAN_SetTxMsgBuff(volatile uint32 * const pMbAddr,
                          const Flexcan_Ip_MsbuffCodeStatusType * cs,
                          uint32 msgId,
                          const uint8 * msgData,
                          const boolean isRemote
                         )
{
    uint32 Flexcan_Mb_Config = 0;
    uint32 DataByte;
    uint8 Dlc_Value;
    uint8 Payload_Size;
    volatile uint32 * Flexcan_Mb = pMbAddr;
    volatile uint32 * Flexcan_Mb_Id   = &Flexcan_Mb[1];
    volatile uint8 * Flexcan_Mb_Data = (volatile uint8*)(&Flexcan_Mb[2]);
    volatile uint32 * Flexcan_Mb_Data_32 = &Flexcan_Mb[2];
    const uint32 * MsgData_32 = (const uint32*)msgData;


    /* Clean up the arbitration field area and set TxMB Inactive */
    *Flexcan_Mb = (uint32)((((uint32)FLEXCAN_TX_INACTIVE & (uint32)0x1F) << (uint8)FLEXCAN_IP_CS_CODE_SHIFT) & (uint32)FLEXCAN_IP_CS_CODE_MASK);
    *Flexcan_Mb_Id = 0;

    /* Compute the value of the DLC field */
    Dlc_Value = FlexCAN_ComputeDLCValue((uint8)cs->dataLen);
    /* Copy user's buffer into the message buffer data area */
    if (msgData != NULL_PTR)
    {

        for (DataByte = 0; DataByte < (cs->dataLen & ~3U); DataByte += 4U)
        {
            FLEXCAN_IP_SWAP_BYTES_IN_WORD((MsgData_32[DataByte >> 2U]), (Flexcan_Mb_Data_32[DataByte >> 2U]));
        }
        for ( ; DataByte < cs->dataLen; DataByte++)
        {
            Flexcan_Mb_Data[FLEXCAN_IP_SWAP_BYTES_IN_WORD_INDEX(DataByte)] =  msgData[DataByte];
        }
    #if (FLEXCAN_IP_FEATURE_HAS_FD == STD_ON)
        Payload_Size = FlexCAN_ComputePayloadSize(Dlc_Value);
        /* Add padding, if needed */
        for (DataByte = cs->dataLen; DataByte < Payload_Size; DataByte++)
        {
            Flexcan_Mb_Data[FLEXCAN_IP_SWAP_BYTES_IN_WORD_INDEX(DataByte)] = cs->fd_padding;
        }
    #endif /* FLEXCAN_IP_FEATURE_HAS_FD */
    }
    /* Set the ID according the format structure */
    if (FLEXCAN_MSG_ID_EXT == cs->msgIdType)
    {
        /* ID [28-0] */
        *Flexcan_Mb_Id &= ~(FLEXCAN_IP_ID_STD_MASK | FLEXCAN_IP_ID_EXT_MASK);
        *Flexcan_Mb_Id |= (msgId & (FLEXCAN_IP_ID_STD_MASK | FLEXCAN_IP_ID_EXT_MASK));
        /* Set IDE and SRR bit*/
        Flexcan_Mb_Config |= (FLEXCAN_IP_CS_IDE_MASK | FLEXCAN_IP_CS_SRR_MASK);
    }
    if (FLEXCAN_MSG_ID_STD == cs->msgIdType)
    {
        /* ID[28-18] */
        *Flexcan_Mb_Id &= ~FLEXCAN_IP_ID_STD_MASK;
        *Flexcan_Mb_Id |= (msgId << FLEXCAN_IP_ID_STD_SHIFT) & FLEXCAN_IP_ID_STD_MASK;
        /* make sure IDE and SRR are not set */
        Flexcan_Mb_Config &= ~(FLEXCAN_IP_CS_IDE_MASK | FLEXCAN_IP_CS_SRR_MASK);
    }
    /* Set the length of data in bytes */
    Flexcan_Mb_Config &= ~FLEXCAN_IP_CS_DLC_MASK;
    Flexcan_Mb_Config |= ((uint32)Dlc_Value << FLEXCAN_IP_CS_DLC_SHIFT) & FLEXCAN_IP_CS_DLC_MASK;
    /* Set MB CODE */
    if (cs->code != (uint32)FLEXCAN_TX_NOT_USED)
    {
        if ((uint32)FLEXCAN_TX_REMOTE == cs->code)
        {
            /* Set RTR bit */
            Flexcan_Mb_Config |= FLEXCAN_IP_CS_RTR_MASK;
        }
        else
        {
            if (TRUE == isRemote)
            {
                /* Set RTR bit */
                Flexcan_Mb_Config |= FLEXCAN_IP_CS_RTR_MASK;
            }
        }
        /* Reset the code */
        Flexcan_Mb_Config &= ~FLEXCAN_IP_CS_CODE_MASK;
        /* Set the code */
        if (cs->fd_enable)
        {
            Flexcan_Mb_Config |= ((cs->code << FLEXCAN_IP_CS_CODE_SHIFT) & FLEXCAN_IP_CS_CODE_MASK) | FLEXCAN_IP_CS_EDL_MASK;
            /* In case of FD frame not supported RTR */
            Flexcan_Mb_Config &= ~FLEXCAN_IP_CS_RTR_MASK;
        }
        else
        {
            Flexcan_Mb_Config |= (cs->code << FLEXCAN_IP_CS_CODE_SHIFT) & FLEXCAN_IP_CS_CODE_MASK;
        }

        if (cs->enable_brs)
        {
            Flexcan_Mb_Config |= FLEXCAN_IP_CS_BRS_MASK;
        }
        *Flexcan_Mb |= Flexcan_Mb_Config;
    }
}



/*FUNCTION**********************************************************************
 *
 * Function Name : FlexCAN_SetEnhancedNominalTimeSegments
 * Description   : Initialize basically controller.
 *
 *END**************************************************************************/
void FlexCAN_SetEnhancedNominalTimeSegments(FLEXCAN_Type * pBase, const Flexcan_Ip_TimeSegmentType * timeSeg)
{

    (pBase->ENCBT) = ((pBase->ENCBT) & ~(FLEXCAN_ENCBT_NTSEG1_MASK | FLEXCAN_ENCBT_NTSEG2_MASK | FLEXCAN_ENCBT_NRJW_MASK));

    (pBase->ENCBT) = ((pBase->ENCBT) |(FLEXCAN_ENCBT_NTSEG1(timeSeg->phaseSeg1 + timeSeg->propSeg + 1U) |
                                     FLEXCAN_ENCBT_NTSEG2(timeSeg->phaseSeg2) |
                                     FLEXCAN_ENCBT_NRJW(timeSeg->rJumpwidth)
                                    )
                    );
    (pBase->EPRS) = (pBase->EPRS & ~FLEXCAN_EPRS_ENPRESDIV_MASK);
    (pBase->EPRS) |= FLEXCAN_EPRS_ENPRESDIV(timeSeg->preDivider);
}

/*!
 * @brief Get the FlexCAN Enhanced time segments for nominal bit rate.
 *
 * @param   base The FlexCAN base address
 * @param   timeSeg    FlexCAN time segments, which need to be set for the bit rate.
 */
static inline void FlexCAN_GetEnhancedNominalTimeSegments(const FLEXCAN_Type * base, Flexcan_Ip_TimeSegmentType * timeSeg)
{
    timeSeg->propSeg = 0;
    timeSeg->preDivider = ((base->EPRS & FLEXCAN_EPRS_ENPRESDIV_MASK) >> FLEXCAN_EPRS_ENPRESDIV_SHIFT);
    timeSeg->phaseSeg1 = ((base->ENCBT & FLEXCAN_ENCBT_NTSEG1_MASK) >> FLEXCAN_ENCBT_NTSEG1_SHIFT);
    timeSeg->phaseSeg2 = ((base->ENCBT & FLEXCAN_ENCBT_NTSEG2_MASK) >> FLEXCAN_ENCBT_NTSEG2_SHIFT);
    timeSeg->rJumpwidth = ((base->ENCBT & FLEXCAN_ENCBT_NRJW_MASK) >> FLEXCAN_ENCBT_NRJW_SHIFT);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FlexCAN_InitController
 * Description   : Initialize basically controller.
 *
 * This is not a public API as it is called from other driver functions.
 *END**************************************************************************/
Hscg_Fw_ReturnType FlexCAN_InitController(FLEXCAN_Type * pBase, Hscg_Can_InitCmdType* pChannelInitConfig)
{
    Flexcan_Ip_StatusType eResult = FLEXCAN_STATUS_SUCCESS;

    if (FlexCAN_IsEnabled(pBase))
    {
        /* To enter Disable Mode requires FreezMode first */
        eResult = FlexCAN_EnterFreezeMode(pBase);
        if (FLEXCAN_STATUS_SUCCESS == eResult)
        {
            eResult = FlexCAN_Disable(pBase);
            hprintf(DEBUG, "FlexCAN_Disable\r\n");
        }
    }

    if (FLEXCAN_STATUS_SUCCESS == eResult)
    {
        /* Enable FlexCAN Module need to perform SoftReset & ClearRam */
        pBase->MCR &= ~FLEXCAN_MCR_MDIS_MASK;
        /* Initialize FLEXCAN device */
        eResult = FlexCAN_Init(pBase);

        if (eResult != FLEXCAN_STATUS_SUCCESS)
        {
            hprintf(DEBUG, "FlexCAN_Init Error!!!\r\n");
            /* To enter Disable Mode requires FreezMode first */
            (void)FlexCAN_EnterFreezeMode(pBase);
            (void)FlexCAN_Disable(pBase);
        }
        else
        {
            //hprintf(DEBUG, "FlexCAN_Init Success!!!\r\n");
            FlexCAN_ConfigCtrlOptions(pBase,pChannelInitConfig->u32CtrlConfig);
            eResult = FlexCAN_InitCtroll(pBase, (Hscg_Can_InitCmdType*)pChannelInitConfig->u32CtrlConfig);
        }
    }
    //hprintf(DEBUG, "Channel:%d,u32CtrlConfig:%.8x\r\n", aChannel,pChannelInitConfig->u32CtrlConfig);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FlexCAN_ChangeBaudrate
 * Description   : 
 *
 * This is not a public API as it is called from other driver functions.
 *END**************************************************************************/
void FlexCAN_ChangeBaudrate(FLEXCAN_Type * pBase, Can_HSCG_ControllerBaudrateConfigType* pBpsCfgPtr)
{
    // used enhanced bit timing
    pBase->CTRL2 = (pBase->CTRL2 & ~FLEXCAN_CTRL2_BTE_MASK) | FLEXCAN_CTRL2_BTE(1);

    // Normal
    // presdiv
    pBase->EPRS  = (pBase->EPRS & ~FLEXCAN_EPRS_ENPRESDIV_MASK) | FLEXCAN_EPRS_ENPRESDIV(1);
    // seg1
    pBase->ENCBT = (pBase->ENCBT & ~FLEXCAN_ENCBT_NTSEG1_MASK) | FLEXCAN_ENCBT_NTSEG1(1);
    // seg2
    pBase->ENCBT = (pBase->ENCBT & ~FLEXCAN_ENCBT_NTSEG2_MASK) | FLEXCAN_ENCBT_NTSEG2(1);
    // RJW
    pBase->ENCBT = (pBase->ENCBT & ~FLEXCAN_ENCBT_NRJW_MASK) | FLEXCAN_ENCBT_NRJW(2);

    // Data
    // Normal
    {
        // presdiv
        pBase->EPRS  = (pBase->EPRS & ~FLEXCAN_EPRS_ENPRESDIV_MASK) | FLEXCAN_EPRS_ENPRESDIV(pBpsCfgPtr->bitrate_normal.preDivider);
        // seg1
        pBase->ENCBT = (pBase->ENCBT & ~FLEXCAN_ENCBT_NTSEG1_MASK) | FLEXCAN_ENCBT_NTSEG1(pBpsCfgPtr->bitrate_normal.phaseSeg1);
        // seg2
        pBase->ENCBT = (pBase->ENCBT & ~FLEXCAN_ENCBT_NTSEG2_MASK) | FLEXCAN_ENCBT_NTSEG2(pBpsCfgPtr->bitrate_normal.phaseSeg2);
        // RJW
        pBase->ENCBT = (pBase->ENCBT & ~FLEXCAN_ENCBT_NRJW_MASK) | FLEXCAN_ENCBT_NRJW(pBpsCfgPtr->bitrate_normal.rJumpwidth);
    }

    // Data
    {
        // presdiv
        pBase->EPRS  = (pBase->EPRS & ~FLEXCAN_EPRS_EDPRESDIV_MASK) | FLEXCAN_EPRS_EDPRESDIV(pBpsCfgPtr->bitrate_data.preDivider);
        // seg1
        pBase->EDCBT = (pBase->EDCBT & ~FLEXCAN_EDCBT_DTSEG1_MASK) | FLEXCAN_EDCBT_DTSEG1(pBpsCfgPtr->bitrate_data.phaseSeg1);
        // seg2
        pBase->EDCBT = (pBase->EDCBT & ~FLEXCAN_EDCBT_DTSEG2_MASK) | FLEXCAN_EDCBT_DTSEG2(pBpsCfgPtr->bitrate_data.phaseSeg2);
        // SJW
        pBase->EDCBT = (pBase->EDCBT & ~FLEXCAN_EDCBT_DRJW_MASK) | FLEXCAN_EDCBT_DRJW(pBpsCfgPtr->bitrate_data.rJumpwidth);
    }

    // hprintf(DEBUG, "canfd config:%.8x\r\n",pBpsCfgPtr->fd_config);
    // hprintf(DEBUG, "canfd normal:%.8x %.8x %.8x %.8x %.8x\r\n",pBpsCfgPtr->bitrate_normal.preDivider,  //2-1
    //                                                            pBpsCfgPtr->bitrate_normal.propSeg,      //0
    //                                                            pBpsCfgPtr->bitrate_normal.phaseSeg1,    //59-1
    //                                                            pBpsCfgPtr->bitrate_normal.phaseSeg2,    //20-1
    //                                                            pBpsCfgPtr->bitrate_normal.rJumpwidth);  //20-1

    // hprintf(DEBUG, "canfd data:%.8x %.8x %.8x %.8x %.8x\r\n",  pBpsCfgPtr->bitrate_data.preDivider,  //4-1
    //                                                            pBpsCfgPtr->bitrate_data.propSeg,       //0
    //                                                            pBpsCfgPtr->bitrate_data.phaseSeg1,     //15-1
    //                                                            pBpsCfgPtr->bitrate_data.phaseSeg2,     //4-1
    //                                                            pBpsCfgPtr->bitrate_data.rJumpwidth);   //4-1
}


/*FUNCTION**********************************************************************
 *
 * Function Name : FlexCAN_ChangeBaudrate
 * Description   : 
 *
 * This is not a public API as it is called from other driver functions.
 *END**************************************************************************/
void FlexCAN_SetEnhancedFifoFilters(FLEXCAN_Type * pBase, Hscg_Can_EnhancedRxFifoFilterType* pFilter)
{
    uint32 index = 0x00;
    uint32 u32ExtCount = 0x00;
    uint32 u32StdCount = 0x00;
    uint32 u32NFE = 0x00;
    uint32 ExtIndex = 0x00;
    uint32 StdIndex = 0x00;
    uint32 u32Temp;

    // Configure the Enhanced Rx FIFO watermark
    pBase->ERFCR = (pBase->ERFCR & ~FLEXCAN_ERFCR_ERFWM_MASK) | FLEXCAN_ERFCR_ERFWM(31);

    // Configure DMALW
    pBase->ERFCR = (pBase->ERFCR & ~FLEXCAN_ERFCR_DMALW_MASK) | FLEXCAN_ERFCR_DMALW(19);

    // NEXIF
    if(pFilter->ExtCount%2)
    {
        u32ExtCount = pFilter->ExtCount+1;
    }
    else
    {
        u32ExtCount = pFilter->ExtCount;
    }
    pBase->ERFCR = (pBase->ERFCR & ~FLEXCAN_ERFCR_NEXIF_MASK) | FLEXCAN_ERFCR_NEXIF(u32ExtCount/2);

    // NFE
    if(pFilter->StdCount%4)
    {
        u32StdCount = pFilter->StdCount+3;
    }
    else
    {
        u32StdCount = pFilter->StdCount;
    }
    u32StdCount = u32ExtCount/2 + u32StdCount/4-1;
    pBase->ERFCR = (pBase->ERFCR & ~FLEXCAN_ERFCR_NFE_MASK) | FLEXCAN_ERFCR_NFE(u32StdCount);
    //hprintf(DEBUG, "ExtCount:%d StdCount:%d NEXIF:%d NFE:%d\r\n",pFilter->ExtCount,pFilter->StdCount,u32ExtCount/2,u32StdCount);


    // Ext
    for(index=0x00; index<pFilter->ExtCount; index++)
    {
        u32Temp = pFilter->pExtFilter[index].id;
        if(0x00 == index%2)
        {
            u32Temp |= 0x80000000u;
        }
        pBase->ERFFEL[index] = u32Temp;

        //hprintf(DEBUG, "ERFFEL[%d]:%.8x ERFFEL[%d]:%.8x\r\n",index,pFilter->pExtFilter[index].id,index,u32Temp);
    }

    // Check Ext Filter End
    ExtIndex = index;
    if(pFilter->ExtCount%2)
    {
        ExtIndex++;
        pBase->ERFFEL[ExtIndex] = pFilter->pExtFilter[0].id;
    }

    // Std
    for(index=0x00; index<pFilter->StdCount/4; index++)
    {
        u32NFE = ((uint32)pFilter->pStdFilter[index].id<<0)+((uint32)pFilter->pStdFilter[index+1].id<<16);
        u32NFE |= 0x80000000;
        //hprintf(DEBUG, "ExtIndex+2*index+0 = %d\r\n", ExtIndex+2*index+0);
        pBase->ERFFEL[ExtIndex+2*index+0] = u32NFE;
       // hprintf(DEBUG, "u32NFE:%.8x\r\n",u32NFE);

        u32NFE = ((uint32)pFilter->pStdFilter[index+2].id<<0)+((uint32)pFilter->pStdFilter[index+3].id<<16);
        u32NFE |= 0x80000000;
        //hprintf(DEBUG, "ExtIndex+2*index+1 = %d\r\n", ExtIndex+2*index+1);
        pBase->ERFFEL[ExtIndex+2*index+1] = u32NFE;
        //hprintf(DEBUG, "u32NFE:%.8x\r\n",u32NFE);
    }
    // Check Std Filter End
    StdIndex = index;
    if(pFilter->StdCount%4)
    {
        StdIndex++;
        if(0x01 == pFilter->StdCount%4)
        {
            u32NFE = ((uint32)pFilter->pStdFilter[StdIndex].id<<0)+((uint32)pFilter->pStdFilter[StdIndex].id<<16);
            u32NFE |= 0x80000000;
            //hprintf(DEBUG, "ExtIndex+2*StdIndex+0 = %d \r\n", ExtIndex+2*StdIndex+0);
            pBase->ERFFEL[ExtIndex+2*StdIndex+0] = u32NFE;
            //hprintf(DEBUG, "u32NFE:%.8x\r\n",u32NFE);

            //hprintf(DEBUG, "ExtIndex+2*StdIndex+1 = %d \r\n", ExtIndex+2*StdIndex+1);
            pBase->ERFFEL[ExtIndex+2*StdIndex+1] = u32NFE;
            //hprintf(DEBUG, "u32NFE:%.8x\r\n",u32NFE);
        }
        else if(0x02 == pFilter->StdCount%4)
        {
            u32NFE = ((uint32)pFilter->pStdFilter[StdIndex].id<<0)+((uint32)pFilter->pStdFilter[StdIndex+1].id<<16);
            u32NFE |= 0x80000000;
            pBase->ERFFEL[ExtIndex+2*StdIndex+0] = u32NFE;
            //hprintf(DEBUG, "u32NFE:%.8x\r\n",u32NFE);

            pBase->ERFFEL[ExtIndex+2*StdIndex+1] = u32NFE;
            //hprintf(DEBUG, "u32NFE:%.8x\r\n",u32NFE);
        }
        else if(0x03 == pFilter->StdCount%4)
        {
            u32NFE = ((uint32)pFilter->pStdFilter[StdIndex].id<<0)+((uint32)pFilter->pStdFilter[StdIndex+1].id<<16);
            u32NFE |= 0x80000000;
            pBase->ERFFEL[ExtIndex+2*StdIndex+0] = u32NFE;
            //hprintf(DEBUG, "u32NFE:%.8x\r\n",u32NFE);

            u32NFE = ((uint32)pFilter->pStdFilter[StdIndex+2].id<<0)+((uint32)pFilter->pStdFilter[StdIndex+2].id<<16);
            u32NFE |= 0x80000000;
            pBase->ERFFEL[ExtIndex+2*StdIndex+1] = u32NFE;
            //hprintf(DEBUG, "u32NFE:%.8x\r\n",u32NFE);
        }
        else
        {
            // Err
        }

        // for(index=0; index<10; index++){
        //     hprintf(DEBUG, "pBase->ERFFEL[%d] = 0x%x \r\n", index, pBase->ERFFEL[index]);
        // }

    }
}

void FlexCAN_Transmit(FLEXCAN_Type *base,
                        uint32 mbIdx,
                        uint32 msgCtrl,
                        uint32 msgId,
                        const uint8 *msgData,
                        uint32 dataLen)
{
    volatile uint32 *pMbAddr;
    volatile uint32 *Flexcan_Mb;
    volatile uint32 *Flexcan_Mb_Id;
    volatile uint32 *Flexcan_Mb_Data_32;
    const uint32 *MsgData_32 = (const uint32 *)msgData;
    uint32 DataByte;

    FlexCAN_ClearMsgBuffIntStatusFlag(base, mbIdx);
    pMbAddr = FlexCAN_GetMsgBuffRegion(base, mbIdx);
    Flexcan_Mb = pMbAddr;
    Flexcan_Mb_Id = &Flexcan_Mb[1];
    Flexcan_Mb_Data_32 = &Flexcan_Mb[2];

    if ((msgCtrl & FLEXCAN_IP_CS_IDE_MASK) != 0U) {
        /* ID [28-0] */
        *Flexcan_Mb_Id &= ~(FLEXCAN_IP_ID_STD_MASK | FLEXCAN_IP_ID_EXT_MASK);
        *Flexcan_Mb_Id |= (msgId & (FLEXCAN_IP_ID_STD_MASK | FLEXCAN_IP_ID_EXT_MASK));
    } else {
        /* ID[28-18] */
        *Flexcan_Mb_Id &= ~FLEXCAN_IP_ID_STD_MASK;
        *Flexcan_Mb_Id |= (msgId << FLEXCAN_IP_ID_STD_SHIFT) & FLEXCAN_IP_ID_STD_MASK;
    }

    /**
     *
     * 这里需要注意，往FLEXCAN硬件写值的时候，必须以u32为单位，否则可能写不进去
     */
    for (DataByte = 0; DataByte < (dataLen + 3U) / 4; DataByte++) {
        Flexcan_Mb_Data_32[DataByte] = MsgData_32[DataByte];
    }

    msgCtrl &= ~FLEXCAN_IP_CS_CODE_MASK;
    msgCtrl |= (FLEXCAN_TX_DATA << FLEXCAN_IP_CS_CODE_SHIFT) & FLEXCAN_IP_CS_CODE_MASK;

    STATISTICS_UPDATE_PACKET_ETH2CAN_TIMESTAMP(TIMESTAMP_PACKET_ETH2CAN_SENDTO_CAN_CONTROLLER_END);
    *Flexcan_Mb = msgCtrl;
}

Flexcan_Ip_StatusType FlexCAN_EnhancedFifoReceive(FLEXCAN_Type *base,
                                                     uint32 *cs,
                                                     uint32 *msgId,
                                                     uint8 *data,
                                                     uint8 *dataLen,
                                                     uint8 *filterId)
{
    volatile const uint32 * Flexcan_Mb = (uint32 *)((Flexcan_Ip_PtrSizeType)base + (uint32)FLEXCAN_IP_FEAtURE_ENHANCED_FIFO_OFFSET);
    volatile const uint32 * Flexcan_Mb_Id = &Flexcan_Mb[1];
    volatile const uint32 * Flexcan_Mb_Data_32 = &Flexcan_Mb[2];
    uint32 msgCtrl;
    uint8 Idhit_Offset;
    uint8 Dlc_Value;
    uint8 Payload_Size;

    if (!FlexCAN_IsRxFifoDataAvailable(base)) {
        return FLEXCAN_STATUS_ERROR;
    }

    msgCtrl = *Flexcan_Mb;
    *cs = msgCtrl;
    if ((msgCtrl & FLEXCAN_IP_CS_IDE_MASK) != 0U) {
        *msgId = *Flexcan_Mb_Id;
    } else {
        *msgId = (*Flexcan_Mb_Id) >> FLEXCAN_IP_ID_STD_SHIFT;
    }

    Dlc_Value = (uint8)(((*Flexcan_Mb)&FLEXCAN_IP_CS_DLC_MASK) >> FLEXCAN_IP_CS_DLC_SHIFT);

    Payload_Size = FlexCAN_ComputePayloadSize(Dlc_Value);
    if ((msgCtrl & FLEXCAN_IP_CS_RTR_MASK) != 0U) {
        Payload_Size = 0U;
    }

    if (Payload_Size > 0) {
        uint8 dw = (Payload_Size % 4 == 0 ? (Payload_Size / 4) : (Payload_Size / 4 + 1));
        memcpy(data, (void*)Flexcan_Mb_Data_32, dw * 4);
    }
    *dataLen = Payload_Size;

    Idhit_Offset = (Payload_Size >> 2U) + (((Payload_Size % 4U) != 0U) ? 1U : 0U);
    *filterId = (uint8)(((Flexcan_Mb_Data_32[Idhit_Offset]) & FLEXCAN_IP_ENHANCED_IDHIT_MASK) >> FLEXCAN_IP_ENHANCED_IDHIT_SHIFT);

    // 清空标志位，硬件开始接收下一帧数据
    base->ERFSR |= FLEXCAN_ERFSR_ERFDA(1);
    base->TIMER;

    return FLEXCAN_STATUS_SUCCESS;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FlexCAN_ReadEnhancedRxFifo
 * Description   : Read Enhanced Rx FIFO data.
 * This function will copy Enhanced Rx FIFO data output into user's buffer.
 *
 *END**************************************************************************/
void FlexCAN_ReadEnhancedRxFifo(FLEXCAN_Type * base, Flexcan_Ip_MsgBuffType * rxFifo)
{
    uint32 DataByte;
    uint32 MbWord;
    uint8 Idhit_Offset;
    volatile const uint32 * Flexcan_Mb = (uint32 *)((Flexcan_Ip_PtrSizeType)base + (uint32)FLEXCAN_IP_FEAtURE_ENHANCED_FIFO_OFFSET);
    volatile const uint32 * Flexcan_Mb_Id = &Flexcan_Mb[1];
    volatile const uint32 * Flexcan_Mb_Data_32 = &Flexcan_Mb[2];
    uint32 * MsgData_32 = NULL_PTR;
    uint8 idHitaux = 0U;
    uint8 filterElement = 0U;

    /* Compute payload size */
    uint8 flexcan_mb_dlc_value = (uint8)(((*Flexcan_Mb) & FLEXCAN_IP_CS_DLC_MASK) >> FLEXCAN_IP_CS_DLC_SHIFT);
    uint8 can_real_payload = FlexCAN_ComputePayloadSize(flexcan_mb_dlc_value);

    MsgData_32 = (uint32 *)(rxFifo->data);
    rxFifo->dataLen = can_real_payload;
    rxFifo->cs = *Flexcan_Mb;

    if ((rxFifo->cs & FLEXCAN_IP_CS_IDE_MASK) != 0U)
    {
        rxFifo->msgId = *Flexcan_Mb_Id;
    }
    else
    {
        rxFifo->msgId = (*Flexcan_Mb_Id) >> FLEXCAN_IP_ID_STD_SHIFT;
    }

    if ((rxFifo->cs & FLEXCAN_IP_CS_RTR_MASK) != 0U)
    {
        can_real_payload = 0U;
    }

    Idhit_Offset = (can_real_payload >> 2U) + (((can_real_payload % 4U) != 0U) ? 1U : 0U);

    /* Extract the IDHIT */
    idHitaux = (uint8)(((Flexcan_Mb_Data_32[Idhit_Offset]) & FLEXCAN_IP_ENHANCED_IDHIT_MASK) >> FLEXCAN_IP_ENHANCED_IDHIT_SHIFT);
#if 1 // no filterIdMap
    rxFifo->id_hit = idHitaux;
#else
	filterElement = ((rxFifo->cs & FLEXCAN_IP_CS_IDE_MASK) == 0U) ? ((uint8)(((base->ERFCR) & FLEXCAN_ERFCR_NEXIF_MASK) >> FLEXCAN_ERFCR_NEXIF_SHIFT) + idHitaux) : idHitaux;
    rxFifo->id_hit = filterIdMap[filterElement];
#endif

    {
        rxFifo->time_stamp = (uint32)(Flexcan_Mb_Data_32[Idhit_Offset + 1U]);
    }


    /* Copy EnhancedRxFIFO data field into user's buffer */
    for (DataByte = 0U; DataByte < can_real_payload; DataByte += 4U)
    {
        MsgData_32[DataByte >> 2U] = Flexcan_Mb_Data_32[DataByte >> 2U];
        // MbWord = Flexcan_Mb_Data_32[DataByte >> 2U];
        // FLEXCAN_IP_SWAP_BYTES_IN_WORD((MbWord), (MsgData_32[DataByte >> 2U]));
    }

    //清空标志位，硬件开始接收下一帧数据
    base->ERFSR |= FLEXCAN_ERFSR_ERFDA(1);
    base->TIMER;
    STATISTICS_UPDATE_PACKET_CAN2ETH_LOOP();
    STATISTICS_UPDATE_PACKET_CAN2CAN_LOOP();

    STATISTICS_UPDATE_PACKET_CAN2ETH_DATA(rxFifo->msgId, rxFifo->data, rxFifo->dataLen);
    STATISTICS_UPDATE_PACKET_CAN2CAN_DATA(rxFifo->msgId, rxFifo->data, rxFifo->dataLen);
    STATISTICS_UPDATE_PACKET_CAN2ETH_TIMESTAMP(TIMESTAMP_PACKET_CAN2ETH_SW_RECV_CAN_PACKET);
    STATISTICS_UPDATE_PACKET_CAN2CAN_TIMESTAMP(TIMESTAMP_PACKET_CAN2CAN_SW_RECV_CAN_PACKET);
}
